package cn.smile.business.wechat.impl;

import cn.smile.bean.dto.notebook.NotebookDTO;
import cn.smile.bean.dto.wechat.*;
import cn.smile.bean.entity.wechat.WechatDevelopConfig;
import cn.smile.bean.form.notebook.QueryNotebookForm;
import cn.smile.bean.form.wechat.api.ArticleDraftForm;
import cn.smile.business.core.IReqWithoutService;
import cn.smile.business.notebook.INotebookService;
import cn.smile.business.wechat.IWeChatApiService;
import cn.smile.business.wechat.IWeChatDevConService;
import cn.smile.commons.constant.NumberConstant;
import cn.smile.commons.constant.RedisKeyConstant;
import cn.smile.commons.constant.WeChatConstant;
import cn.smile.commons.enums.wechat.WeChatPublishStatusEnum;
import cn.smile.commons.exceptions.BusinessException;
import cn.smile.commons.response.MyResponseCode;
import cn.smile.feign.WeChatFeignClient;
import cn.smile.utils.FileUtil;
import cn.smile.utils.RedisUtil;
import com.alibaba.fastjson2.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class WeChatApiServiceImpl implements IWeChatApiService {
    @Resource
    private IReqWithoutService withoutService;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private IWeChatDevConService configService;
    @Resource
    private WeChatFeignClient weChatFeignClient;
    @Resource
    private INotebookService notebookService;

    @Override
    public String getAccessToken(String appId, String appSecret, Boolean refresh) {
        log.info("[WeChatApiServiceImpl].[getAccessToken] ------> 获取微信公众号授权Token Start");
        String accessToken;
        if (refresh) {
            accessToken = this.getAccessToken(appId, appSecret);
        } else {
            String key = String.format(RedisKeyConstant.WE_CHAT_ACCESS_TOKEN_KEY, appId);
            Object bucket = redisUtil.get(key);
            if (ObjectUtils.isEmpty(bucket)) {
                accessToken = this.getAccessToken(appId, appSecret);
            } else {
                accessToken = (String) bucket;
            }
        }

        log.info("[WeChatApiServiceImpl].[getAccessToken] ------> 获取微信公众号授权Token End");
        return accessToken;
    }

    @Override
    public String getAccessToken(String appId, Boolean refresh) {
        WechatDevelopConfigDTO config = configService.getConfigByAppId(appId);
        if (!config.getEnableFlag()) {
            throw new BusinessException(MyResponseCode.WE_CHAT_CONFIG_STOP_ERROR);
        }
        return this.getAccessToken(appId, config.getAppSecret(), refresh);
    }

    @Override
    public String pushArticle(ArticleDraftForm form) {
        log.info("[WeChatApiServiceImpl].[pushArticle] ------> 同步发表到微信公众号 Start");
        /*
        1.上传图片文件到素材库
        2.保存草稿
        3.发布草稿
         */
        List<MediaUploadDTO> mediaList = Lists.newArrayList();
        if (!CollectionUtils.isEmpty(form.getImageList())) {
            for (String url : form.getImageList()) {
                mediaList.add(this.uploadMedia(url, form.getAppId()));
            }
        }
        String draftId = this.addDraft(form, mediaList);
        String publishId = this.pushDraft(draftId, form.getAppId());
        log.info("[WeChatApiServiceImpl].[pushArticle] ------> 同步发表到微信公众号 End");
        return publishId;
    }

    /**
     * 草稿发布
     *
     * @param draftId 草稿ID
     * @param appId   微信公众号AppID
     * @return 微信发布任务ID
     */
    private String pushDraft(String draftId, String appId) {
        log.info("[WeChatApiServiceImpl].[pushDraft] ------> 微信公众号草稿发布 Start");
        String accessToken = this.getAccessToken(appId, Boolean.FALSE);
        String url = String.format(WeChatConstant.PUSH_DRAFT_URL, accessToken);
        Map<String, Object> params = Maps.newHashMap();
        params.put("media_id", draftId);
        String result = withoutService.reqWithOutUrl(url, params, HttpMethod.POST, Boolean.TRUE);
        WeChatPushDTO dto = JSON.parseObject(result, WeChatPushDTO.class);
        if (NumberConstant.ZERO != dto.getErrCode()) {
            log.error("发布草稿内容失败, code = {}, msg = {}", dto.getErrCode(), dto.getErrMsg());
            throw new BusinessException(MyResponseCode.BUSINESS_ERROR, String.format("发布草稿内容失败, code: %s", dto.getErrCode()));
        }
        log.info("[WeChatApiServiceImpl].[pushDraft] ------> 微信公众号草稿发布 End");
        return dto.getPublishId();
    }

    /**
     * 上传文件到微信公众号素材库
     *
     * @param fileUrl 文件URL地址
     * @param appId   微信公众号AppID
     * @return 上传结果
     */
    @Override
    public MediaUploadDTO uploadMedia(String fileUrl, String appId) {
        log.info("[WeChatApiServiceImpl].[uploadMedia] ------> 微信公众号上传永久素材 Start");
        File file = FileUtil.getFileToLocal(fileUrl);
        String accessToken = this.getAccessToken(appId, Boolean.FALSE);
        MultipartFile mediaFile = FileUtil.fileToMultipartFile(file);
        String result = weChatFeignClient.uploadMaterial(accessToken, mediaFile);
        boolean delFlag = file.delete();
        log.info("文件上传结束, 删除本地临时文件: {}", delFlag);
        MediaUploadDTO dto = JSON.parseObject(result, MediaUploadDTO.class);
        if (ObjectUtils.isEmpty(dto) || ObjectUtils.isEmpty(dto.getUrl())) {
            WeChatErrorDTO error = JSON.parseObject(result, WeChatErrorDTO.class);
            log.error("上传永久图片素材失败, code = {}, msg = {}", error.getErrCode(), error.getErrMsg());
            throw new BusinessException(MyResponseCode.BUSINESS_ERROR, String.format("上传永久图片素材失败, code: %s", error.getErrCode()));
        }
        log.info("[WeChatApiServiceImpl].[uploadMedia] ------> 微信公众号上传永久素材 End");
        return dto;
    }

    @Override
    public void pollingPublish() {
        log.info("[WeChatApiServiceImpl].[pollingPublish] ------> 轮询微信公众号图文发布结果 Start");
        List<WechatDevelopConfig> confList = configService.getALlEnableConf();
        if (!CollectionUtils.isEmpty(confList)) {
            Map<String, WechatDevelopConfig> confMap = Maps.newHashMap();
            confList.forEach(conf -> confMap.put(conf.getUserId(), conf));
            QueryNotebookForm form = new QueryNotebookForm();
            form.setUseUser(Boolean.FALSE);
            form.setPublishStatusList(Lists.newArrayList(WeChatPublishStatusEnum.PUBLISHING.getSn()));
            List<NotebookDTO> notebookList = notebookService.getList(form);
            if (!CollectionUtils.isEmpty(notebookList)) {
                for (NotebookDTO notebook : notebookList) {
                    if (confMap.containsKey(notebook.getUserId()) && !ObjectUtils.isEmpty(notebook.getPublishId())) {
                        WechatDevelopConfig config = confMap.get(notebook.getUserId());
                        FreePublishDTO status = this.getPublishStatus(notebook.getPublishId(), config.getAppId());
                        if (!ObjectUtils.isEmpty(status) && !ObjectUtils.isEmpty(status.getPublishStatus())) {
                            switch (status.getPublishStatus()) {
                                case NumberConstant.ZERO:
                                    //微信状态-成功
                                    notebook.setPublishStatus(WeChatPublishStatusEnum.PUBLISH_SUCCESS.getSn());
                                    notebook.setArticleId(status.getArticleId());
                                    notebookService.update(notebook);
                                    break;
                                case NumberConstant.TWO:
                                    notebook.setPublishStatus(WeChatPublishStatusEnum.PUBLISH_FAILURE.getSn());
                                    notebook.setPublishErrorMsg("原创失败");
                                    notebookService.update(notebook);
                                    break;
                                case NumberConstant.THREE:
                                    notebook.setPublishStatus(WeChatPublishStatusEnum.PUBLISH_FAILURE.getSn());
                                    notebook.setPublishErrorMsg("常规失败");
                                    notebookService.update(notebook);
                                    break;
                                case NumberConstant.FOUR:
                                    notebook.setPublishStatus(WeChatPublishStatusEnum.PUBLISH_FAILURE.getSn());
                                    notebook.setPublishErrorMsg("平台审核不通过");
                                    notebookService.update(notebook);
                                    break;
                                case NumberConstant.FIVE:
                                    notebook.setPublishStatus(WeChatPublishStatusEnum.PUBLISH_FAILURE.getSn());
                                    notebook.setPublishErrorMsg("成功后用户删除所有文章");
                                    notebookService.update(notebook);
                                    break;
                                case NumberConstant.SIX:
                                    notebook.setPublishStatus(WeChatPublishStatusEnum.PUBLISH_FAILURE.getSn());
                                    notebook.setPublishErrorMsg("成功后系统封禁所有文章");
                                    notebookService.update(notebook);
                                    break;
                                case NumberConstant.ONE:
                                    //微信状态-发布中
                                default:
                            }
                        }
                    }
                }
            }
        }
        log.info("[WeChatApiServiceImpl].[pollingPublish] ------> 轮询微信公众号图文发布结果 End");
    }

    /**
     * 获取微信公众号发布结果
     *
     * @param publishId 发布ID
     * @param appId     微信公众号AppID
     * @return 微信返回状态
     */
    private FreePublishDTO getPublishStatus(String publishId, String appId) {
        String accessToken = this.getAccessToken(appId, Boolean.FALSE);
        String url = String.format(WeChatConstant.FREE_PUBLISH_URL, accessToken);
        Map<String, Object> params = Maps.newHashMap();
        params.put("publish_id", publishId);
        String result = withoutService.reqWithOutUrl(url, params, HttpMethod.POST, Boolean.TRUE);
        return JSON.parseObject(result, FreePublishDTO.class);
    }

    /**
     * 保存微信公众号图文草稿
     *
     * @param form      图文草稿参数
     * @param mediaList 素材集合
     * @return 草稿ID
     */
    private String addDraft(ArticleDraftForm form, List<MediaUploadDTO> mediaList) {
        String accessToken = this.getAccessToken(form.getAppId(), Boolean.FALSE);
        String url = String.format(WeChatConstant.ADD_DRAFT_URL, accessToken);

        Map<String, Object> article = Maps.newHashMap();
        article.put("title", form.getTitle());
        article.put("author", form.getAuthor());
        article.put("content", this.getContentValue(form.getContent(), mediaList));
        article.put("thumb_media_id", mediaList.get(NumberConstant.ZERO).getMediaId());
        Map<String, Object> params = Maps.newHashMap();
        params.put("articles", Lists.newArrayList(article));
        String result = withoutService.reqWithOutUrl(url, params, HttpMethod.POST, Boolean.TRUE);
        AddDraftDTO dto = JSON.parseObject(result, AddDraftDTO.class);
        if (ObjectUtils.isEmpty(dto) || ObjectUtils.isEmpty(dto.getMediaId())) {
            WeChatErrorDTO error = JSON.parseObject(result, WeChatErrorDTO.class);
            log.error("微信公众号新增草稿失败, code = {}, msg = {}", error.getErrCode(), error.getErrMsg());
            throw new BusinessException(MyResponseCode.BUSINESS_ERROR, String.format("微信公众号新增草稿失败, code: %s", error.getErrCode()));
        }
        return dto.getMediaId();
    }

    /**
     * 组装带图片的富文本内容
     *
     * @param content   文字内容
     * @param mediaList 图片资源
     * @return 富文本字符串
     */
    private String getContentValue(String content, List<MediaUploadDTO> mediaList) {
        StringBuilder value = new StringBuilder("<html><body>");
        value.append("<p>").append(content).append("</p><br/>");
        for (MediaUploadDTO media : mediaList) {
            value.append("<img src='").append(media.getUrl()).append("'><br/><br/>");
        }
        value.append("</body></html>");
        return value.toString();
    }

    /**
     * 请求外部接口获取微信公众号授权Token
     *
     * @param appId     微信公众号 AppID
     * @param appSecret 微信公众号 AppSecret
     * @return 授权访问Token
     */
    private String getAccessToken(String appId, String appSecret) {
        String url = String.format(WeChatConstant.ACCESS_TOKEN_URL, appId, appSecret);
        String result = withoutService.reqWithOutUrl(url, Maps.newHashMap(), HttpMethod.GET, Boolean.TRUE);
        WeChatTokenDTO dto = JSON.parseObject(result, WeChatTokenDTO.class);
        if (!ObjectUtils.isEmpty(dto) && !ObjectUtils.isEmpty(dto.getAccessToken())) {
            String key = String.format(RedisKeyConstant.WE_CHAT_ACCESS_TOKEN_KEY, appId);
            redisUtil.set(key, dto.getAccessToken(), RedisKeyConstant.WE_CHAT_ACCESS_TOKEN_TIMEOUT);
        } else {
            WeChatErrorDTO error = JSON.parseObject(result, WeChatErrorDTO.class);
            log.error("获取微信授权码异常, code = {}, msg = {}", error.getErrCode(), error.getErrMsg());
            throw new BusinessException(MyResponseCode.BUSINESS_ERROR, String.format("获取授权码失败, code: %s", error.getErrCode()));
        }
        return dto.getAccessToken();
    }
}
